home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / util / moni / Scout-src.lha / source / objects / scout_locks.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-09-17  |  18.6 KB  |  551 lines

  1. /**
  2.  * Scout - The Amiga System Monitor
  3.  *
  4.  *------------------------------------------------------------------
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * You must not use this source code to gain profit of any kind!
  21.  *
  22.  *------------------------------------------------------------------
  23.  *
  24.  * @author Andreas Gelhausen
  25.  * @author Richard Körber <rkoerber@gmx.de>
  26.  */
  27.  
  28. #include "system_headers.h"
  29.  
  30. struct LocksCallbackUserData {
  31.     APTR ud_List;
  32.     APTR ud_Application;
  33.     APTR ud_Status;
  34.     UBYTE *ud_Pattern;
  35.     ULONG ud_Shown;
  36.     ULONG ud_Hidden;
  37.     BPTR ud_Handle;
  38. };
  39.  
  40. static __asm __saveds LONG locklist_con2func(register __a2 Object *obj, register __a1 struct NList_ConstructMessage *msg, register __a0 struct Hook *hook)
  41. {
  42.     return AllocListEntry(msg->pool, msg->entry, sizeof(struct LockEntry));
  43. }
  44.  
  45. MakeHook(locklist_con2hook, locklist_con2func);
  46.  
  47. static __asm __saveds LONG locklist_des2func(register __a2 Object *obj, register __a1 struct NList_DestructMessage *msg, register __a0 struct Hook *hook)
  48. {
  49.     FreeListEntry(msg->pool, &msg->entry);
  50.  
  51.     return 0;
  52. }
  53.  
  54. MakeHook(locklist_des2hook, locklist_des2func);
  55.  
  56. static __asm __saveds LONG locklist_dsp2func(register __a2 Object *obj, register __a1 struct NList_DisplayMessage *msg, register __a0 struct Hook *hook)
  57. {
  58.     struct LockEntry *le = (struct LockEntry *)msg->entry;
  59.  
  60.     if (le) {
  61.         msg->strings[0] = le->le_Address;
  62.         msg->strings[1] = le->le_Access;
  63.         msg->strings[2] = le->le_Path;
  64.     } else {
  65.         msg->strings[0] = "Address";
  66.         msg->strings[1] = "Access";
  67.         msg->strings[2] = "Path";
  68.         msg->preparses[0] = MUIX_B;
  69.         msg->preparses[1] = MUIX_B;
  70.         msg->preparses[2] = MUIX_B;
  71.     }
  72.  
  73.     return 0;
  74. }
  75.  
  76. MakeHook(locklist_dsp2hook, locklist_dsp2func);
  77.  
  78. static LONG locklist_cmp2colfunc( struct LockEntry *le1,
  79.                                   struct LockEntry *le2,
  80.                                   ULONG column )
  81. {
  82.     LONG cmp = 0;
  83.  
  84.     switch (column) {
  85.         case 0: cmp = stricmp(le1->le_Address, le2->le_Address); break;
  86.         case 1: cmp = stricmp(le1->le_Access, le2->le_Access); break;
  87.         case 2: cmp = stricmp(le1->le_Path, le2->le_Path); if (cmp == 0) cmp = stricmp(le1->le_Address, le2->le_Address); break;
  88.     }
  89.  
  90.     return cmp;
  91. }
  92.  
  93. static __asm __saveds LONG locklist_cmp2func(register __a2 Object *obj, register __a1 struct NList_CompareMessage *msg, register __a0 struct Hook *hook)
  94. {
  95.     LONG cmp;
  96.     struct LockEntry *le1, *le2;
  97.     ULONG col1, col2;
  98.  
  99.     le1 = (struct LockEntry *)msg->entry1;
  100.     le2 = (struct LockEntry *)msg->entry2;
  101.     col1 = msg->sort_type & MUIV_NList_TitleMark_ColMask;
  102.     col2 = msg->sort_type2 & MUIV_NList_TitleMark2_ColMask;
  103.  
  104.     if (msg->sort_type == MUIV_NList_SortType_None) return 0;
  105.  
  106.     if (msg->sort_type & MUIV_NList_TitleMark_TypeMask) {
  107.         cmp = locklist_cmp2colfunc(le2, le1, col1);
  108.     } else {
  109.         cmp = locklist_cmp2colfunc(le1, le2, col1);
  110.     }
  111.  
  112.     if (cmp != 0 || col1 == col2) return cmp;
  113.  
  114.     if (msg->sort_type2 & MUIV_NList_TitleMark2_TypeMask) {
  115.         cmp = locklist_cmp2colfunc(le2, le1, col2);
  116.     } else {
  117.         cmp = locklist_cmp2colfunc(le1, le2, col2);
  118.     }
  119.  
  120.     return cmp;
  121. }
  122.  
  123. MakeHook(locklist_cmp2hook, locklist_cmp2func);
  124.  
  125. static void ReceiveList( void (* callback)( struct LockEntry *le, void *userData ),
  126.                          void *userData )
  127. {
  128.     struct LockEntry *le;
  129.  
  130.     if (le = tbAllocVecPooled(globalPool, sizeof(struct LockEntry))) {
  131.         if (SendDaemon("GetLockList")) {
  132.             while (ReceiveDecodedEntry((UBYTE *)le, sizeof(struct LockEntry))) {
  133.                 callback(le, userData);
  134.             }
  135.         }
  136.  
  137.         tbFreeVecPooled(globalPool, le);
  138.     }
  139. }
  140.  
  141. static void IterateList( void (* callback)( struct LockEntry *le, void *userData ),
  142.                          void *userData )
  143. {
  144.     UBYTE *ppattern, *tmp;
  145.     struct LockEntry *le;
  146.  
  147.     ppattern = tbAllocVecPooled(globalPool, PATTERN_LENGTH);
  148.     tmp = tbAllocVecPooled(globalPool, PATH_LENGTH);
  149.     le = tbAllocVecPooled(globalPool, sizeof(struct LockEntry));
  150.  
  151.     if (ppattern != NULL && tmp != NULL && le != NULL) {
  152.         struct LocksCallbackUserData *ud = (struct LocksCallbackUserData *)userData;
  153.         BOOL patternOk;
  154.  
  155.         if (ud->ud_Pattern == NULL || (ud->ud_Pattern != NULL && ud->ud_Pattern[0] == 0x00)) {
  156.             patternOk = (ParsePatternNoCase("#?", ppattern, PATTERN_LENGTH) != -1);
  157.         } else {
  158.             patternOk = (ParsePatternNoCase(ud->ud_Pattern, ppattern, PATTERN_LENGTH) != -1);
  159.         }
  160.  
  161.         if (patternOk) {
  162.             struct FileInfoBlock *fib;
  163.  
  164.             if (fib = AllocDosObject(DOS_FIB, TAG_DONE)) {
  165.                 struct DosList *dol;
  166.  
  167.                 NoReqOn();
  168.  
  169.                 dol = LockDosList(LDF_READ | LDF_VOLUMES);
  170.  
  171.                 while (dol = NextDosEntry(dol, LDF_VOLUMES)) {
  172.                     BPTR lock;
  173.  
  174.                     b2cstrn(dol->dol_Name, tmp, PATH_LENGTH);
  175.                     strcat (tmp, ":");
  176.  
  177.                     if (lock = Lock(tmp, SHARED_LOCK)) {
  178.                         BOOL erster;
  179.                         BPTR next;
  180.  
  181.                         erster = TRUE;
  182.                         next = (BPTR)NULL;
  183.  
  184.                         while ((next != (BPTR)NULL && next != lock) || erster) {
  185.                             struct FileLock *flock;
  186.  
  187.                             if (erster) next = lock;
  188.                             flock = (struct FileLock *)BADDR(next);
  189.  
  190.                             if (TypeOfMem(flock) == 0) break;
  191.                             if (flock->fl_Volume != MKBADDR(dol)) break;
  192.  
  193.                             if (Examine(next, fib)) {
  194.                                 if (erster) {
  195.                                     stccpy(le->le_Access, "OWN", sizeof(le->le_Access));
  196.                                 } else if (flock->fl_Access == SHARED_LOCK) {
  197.                                     stccpy(le->le_Access, "SHARED", sizeof(le->le_Access));
  198.                                 } else if (flock->fl_Access == EXCLUSIVE_LOCK) {
  199.                                     stccpy(le->le_Access, "EXCLUSIVE", sizeof(le->le_Access));
  200.                                 } else {
  201.                                     _snprintf(le->le_Access, sizeof(le->le_Access), "invalid (%ld)", flock->fl_Access);
  202.                                 }
  203.  
  204.                                 if (flock->fl_Access == EXCLUSIVE_LOCK) {
  205.                                     LONG oldAccess;
  206.  
  207.                                     Forbid();
  208.  
  209.                                     oldAccess = flock->fl_Access;
  210.                                     flock->fl_Access = SHARED_LOCK;
  211.  
  212.                                     NameFromLock(next, le->le_Path, sizeof(le->le_Path));
  213.  
  214.                                     flock->fl_Access = oldAccess;
  215.  
  216.                                     Permit();
  217.                                 } else {
  218.                                     NameFromLock(next, le->le_Path, sizeof(le->le_Path));
  219.                                 }
  220.  
  221.                                 if (MatchPatternNoCase(ppattern, le->le_Path)) {
  222.                                     le->le_Addr = next;
  223.                                     _snprintf(le->le_Address, sizeof(le->le_Access), "$%08lx", flock);
  224.                                     ud->ud_Shown++;
  225.                                 } else {
  226.                                     le->le_Addr = (BPTR)NULL;
  227.                                     ud->ud_Hidden++;
  228.                                 }
  229.  
  230.                                 callback(le, userData);
  231.                             }
  232.  
  233.                             erster = FALSE;
  234.                             next = flock->fl_Link;
  235.                         }
  236.  
  237.                         UnLock(lock);
  238.                     }
  239.                 }
  240.  
  241.                 UnLockDosList(LDF_READ | LDF_VOLUMES);
  242.  
  243.                 NoReqOff();
  244.  
  245.                 FreeDosObject(DOS_FIB, fib);
  246.             }
  247.         }
  248.     }
  249.  
  250.     if (ppattern) tbFreeVecPooled(globalPool, ppattern);
  251.     if (tmp) tbFreeVecPooled(globalPool, tmp);
  252.     if (le) tbFreeVecPooled(globalPool, le);
  253. }
  254.  
  255. static void UpdateCallback( struct LockEntry *le,
  256.                             void *userData )
  257. {
  258.     struct LocksCallbackUserData *ud = (struct LocksCallbackUserData *)userData;
  259.  
  260.     if (le && le->le_Addr) InsertSortedEntry(ud->ud_List, le);
  261.  
  262.     if ((ud->ud_Shown + ud->ud_Hidden) % 32 == 0) {
  263.         MySetContents(ud->ud_Status, "%ld shown, %ld hidden...", ud->ud_Shown, ud->ud_Hidden);
  264.         DoMethod(ud->ud_Application, MUIM_Application_InputBuffered);
  265.     }
  266. }
  267.  
  268. static void PrintCallback( struct LockEntry *le,
  269.                            void *userData )
  270. {
  271.     struct LocksCallbackUserData *ud = (struct LocksCallbackUserData *)userData;
  272.  
  273.     if (le->le_Addr) PrintFOneLine(ud->ud_Handle, " %s  %-12s  %s\n", le->le_Address, le->le_Access, le->le_Path);
  274. }
  275.  
  276. static void SendCallback( struct LockEntry *le,
  277.                           void *userData )
  278. {
  279.     if (le->le_Addr) SendEncodedEntry((UBYTE *)le, sizeof(struct LockEntry));
  280. }
  281.  
  282. static void CountCallback( struct LockEntry *le,
  283.                            void *userData )
  284. {
  285.     // no op, locks are already counted in IterateList()
  286. }
  287.  
  288. static void RemoveCallback( struct LockEntry *le,
  289.                             void *userData )
  290. {
  291.     if (le->le_Addr) UnLock(le->le_Addr);
  292. }
  293.  
  294. static ULONG __saveds mNew( struct IClass *cl,
  295.                             Object *obj,
  296.                             struct opSet *msg )
  297. {
  298.     APTR locklist, locktext, locktext2, lockpattern, updateButton, printButton, removeButton, exitButton;
  299.  
  300.     if (obj = (Object *)DoSuperNew(cl, obj,
  301.         MUIA_HelpNode, LocksText,
  302.         MUIA_Window_ID, MakeID('L','O','C','K'),
  303.         WindowContents, VGroup,
  304.  
  305.             Child, locklist = MyNListviewObject(MakeID('L','O','L','V'), "BAR,BAR,BAR", &locklist_con2hook, &locklist_des2hook, &locklist_dsp2hook, &locklist_cmp2hook, TRUE),
  306.  
  307.             Child, locktext = MyTextObject5(SPACE40),
  308.  
  309.             Child, locktext2 = MyTextObject(),
  310.  
  311.             Child, HGroup,
  312.                 Child, KeyLabel(txtPattern, 'p'),
  313.                 Child, lockpattern = StringObject,
  314.                     MUIA_String_Contents, "#?",
  315.                     MUIA_ControlChar, 'p',
  316.                     MUIA_String_MaxLen, TEXT_LENGTH,
  317.                     MUIA_CycleChain, TRUE,
  318.                     StringFrame,
  319.                 End,
  320.             End,
  321.  
  322.             Child, MyVSpace(4),
  323.  
  324.             Child, HGroup, MUIA_Group_SameSize, TRUE,
  325.                 Child, updateButton = MakeButton(txtUpdate),
  326.                 Child, printButton  = MakeButton(txtPrint),
  327.                 Child, removeButton = MakeButton(txtRemove),
  328.                 Child, exitButton   = MakeButton(txtExit),
  329.             End,
  330.         End,
  331.         TAG_MORE, msg->ops_AttrList))
  332.     {
  333.         struct LocksWinData *lwd = INST_DATA(cl, obj);
  334.         APTR parent;
  335.  
  336.         lwd->lwd_LockList = locklist;
  337.         lwd->lwd_LockText = locktext;
  338.         lwd->lwd_StatusText = locktext2;
  339.         lwd->lwd_PatternString = lockpattern;
  340.         lwd->lwd_RemoveButton = removeButton;
  341.  
  342.         parent = (APTR)GetTagData(MUIA_Window_ParentWindow, (ULONG)NULL, msg->ops_AttrList);
  343.  
  344.         set(obj, MUIA_Window_Title, MyGetWindowTitle("LOCKS", lwd->lwd_Title, sizeof(lwd->lwd_Title)));
  345.         set(obj, MUIA_Window_ActiveObject, lockpattern);
  346.         set(locklist, MUIA_NList_MultiSelect, MUIV_NList_MultiSelect_Default);
  347.         set(removeButton, MUIA_Disabled, TRUE);
  348.  
  349.         DoMethod(parent,       MUIM_Window_AddChildWindow, obj);
  350.         DoMethod(obj,          MUIM_Notify, MUIA_Window_CloseRequest, TRUE,           MUIV_Notify_Application, 5, MUIM_Application_PushMethod, parent, 2, MUIM_Window_RemChildWindow, obj);
  351.         DoMethod(locklist,     MUIM_Notify, MUIA_NList_Active,        MUIV_EveryTime, obj,                     1, MUIM_LocksWin_ListChange);
  352.         DoMethod(lockpattern,  MUIM_Notify, MUIA_String_Acknowledge,  MUIV_EveryTime, obj,                     1, MUIM_LocksWin_Update);
  353.         DoMethod(updateButton, MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_LocksWin_Update);
  354.         DoMethod(printButton,  MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_LocksWin_Print);
  355.         DoMethod(removeButton, MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     1, MUIM_LocksWin_Remove);
  356.         DoMethod(exitButton,   MUIM_Notify, MUIA_Pressed,             FALSE,          obj,                     3, MUIM_Set, MUIA_Window_CloseRequest, TRUE);
  357.         DoMethod(locklist,     MUIM_NList_Sort3, MUIV_NList_Sort3_SortType_2, MUIV_NList_SortTypeAdd_None, MUIV_NList_Sort3_SortType_Both);
  358.     }
  359.  
  360.     return (ULONG)obj;
  361. }
  362.  
  363. static ULONG __saveds mDispose( struct IClass *cl,
  364.                                 Object *obj,
  365.                                 struct opSet *msg )
  366. {
  367.     struct LocksWinData *lwd = INST_DATA(cl, obj);
  368.  
  369.     set(obj, MUIA_Window_Open, FALSE);
  370.     DoMethod(lwd->lwd_LockList, MUIM_NList_Clear);
  371.  
  372.     return (DoSuperMethodA(cl, obj, msg));
  373. }
  374.  
  375. static ULONG __saveds mUpdate( struct IClass *cl,
  376.                                Object *obj,
  377.                                Msg msg )
  378. {
  379.     struct LocksWinData *lwd = INST_DATA(cl, obj);
  380.     struct LocksCallbackUserData ud;
  381.  
  382.     ApplicationSleep(TRUE);
  383.     set(lwd->lwd_LockList, MUIA_NList_Quiet, TRUE);
  384.     DoMethod(lwd->lwd_LockList, MUIM_NList_Clear);
  385.  
  386.     ud.ud_List = lwd->lwd_LockList;
  387.     get(obj, MUIA_ApplicationObject, &ud.ud_Application);
  388.     ud.ud_Status = lwd->lwd_StatusText;
  389.     ud.ud_Shown = 0;
  390.     ud.ud_Hidden = 0;
  391.     get(lwd->lwd_PatternString, MUIA_String_Contents, &ud.ud_Pattern);
  392.  
  393.     if (clientstate) {
  394.         ReceiveList(UpdateCallback, &ud);
  395.     } else {
  396.         IterateList(UpdateCallback, &ud);
  397.     }
  398.  
  399.     lwd->lwd_LocksShown = ud.ud_Shown;
  400.     lwd->lwd_LocksHidden = ud.ud_Hidden;
  401.     MySetContents(lwd->lwd_StatusText, msgLocksShownHiddenDone, ud.ud_Shown, ud.ud_Hidden);
  402.     set(obj, MUIA_Window_ActiveObject, lwd->lwd_LockList);
  403.  
  404.     set(lwd->lwd_LockList, MUIA_NList_Quiet, FALSE);
  405.     set(lwd->lwd_RemoveButton, MUIA_Disabled, TRUE);
  406.     ApplicationSleep(FALSE);
  407.  
  408.     return 0;
  409. }
  410.  
  411. static ULONG __saveds mPrint( struct IClass *cl,
  412.                               Object *obj,
  413.                               Msg msg )
  414. {
  415.     PrintLocks(NULL);
  416.  
  417.     return 0;
  418. }
  419.  
  420. static ULONG __saveds mRemove( struct IClass *cl,
  421.                                Object *obj,
  422.                                Msg msg )
  423. {
  424.     struct LocksWinData *lwd = INST_DATA(cl, obj);
  425.     UBYTE *tmp;
  426.  
  427.     if (tmp = tbAllocVecPooled(globalPool, FILENAME_LENGTH)) {
  428.         ULONG id = MUIV_NList_NextSelected_Start;
  429.         ULONG remMode = 1;
  430.  
  431.         while (TRUE) {
  432.             struct LockEntry *le;
  433.  
  434.             DoMethod(lwd->lwd_LockList, MUIM_NList_NextSelected, &id);
  435.             if (id == MUIV_NList_NextSelected_End) break;
  436.             if (remMode == 0) break;
  437.  
  438.             DoMethod(lwd->lwd_LockList, MUIM_NList_GetEntry, id, &le);
  439.             if (le) {
  440.                 ULONG pos;
  441.  
  442.                 if (remMode != 2) remMode = MyRequest(msgYesAllNoAbort, msgWantToRemoveLock, le->le_Path);
  443.  
  444.                 get(lwd->lwd_LockList, MUIA_NList_Active, &pos);
  445.                 if (pos == id) {
  446.                     set(lwd->lwd_LockList, MUIA_NList_Active, MUIV_List_Active_Off);
  447.                     set(lwd->lwd_RemoveButton, MUIA_Disabled, TRUE);
  448.                 }
  449.  
  450.                 if (remMode == 1 || remMode == 2) {
  451.                     if (MyDoCommand("RemoveLock %s", le->le_Address)) {
  452.                         DoMethod(lwd->lwd_LockList, MUIM_NList_Remove, id);
  453.                         id = MUIV_NList_NextSelected_Start;
  454.  
  455.                         lwd->lwd_LocksShown--;
  456.                         _snprintf(tmp, FILENAME_LENGTH, msgLocksShownHiddenDone, lwd->lwd_LocksShown, lwd->lwd_LocksHidden);
  457.                         set(lwd->lwd_StatusText, MUIA_Text_Contents, tmp);
  458.                     }
  459.                 } else if (remMode == 3) {
  460.                     DoMethod(lwd->lwd_LockList, MUIM_NList_Select, id, MUIV_NList_Select_Off, NULL);
  461.                     id = MUIV_NList_NextSelected_Start;
  462.                 }
  463.             }
  464.         }
  465.  
  466.         tbFreeVecPooled(globalPool, tmp);
  467.     }
  468.  
  469.     return 0;
  470. }
  471.  
  472. static ULONG __saveds mListChange( struct IClass *cl,
  473.                                    Object *obj,
  474.                                    Msg msg )
  475. {
  476.     struct LocksWinData *lwd = INST_DATA(cl, obj);
  477.     struct LockEntry *le;
  478.  
  479.     if (le = (struct LockEntry *)GetActiveEntry(lwd->lwd_LockList)) {
  480.         MySetContents(lwd->lwd_LockText, "%s \"%s\"", le->le_Address, le->le_Path);
  481.         set(lwd->lwd_RemoveButton, MUIA_Disabled, FALSE);
  482.     }
  483.  
  484.     return 0;
  485. }
  486.  
  487. ULONG __asm __saveds LocksWinDispatcher( register __a0 struct IClass *cl,
  488.                                          register __a2 Object *obj,
  489.                                          register __a1 Msg msg )
  490. {
  491.     switch (msg->MethodID) {
  492.         case OM_NEW:                   return (mNew(cl, obj, (APTR)msg));
  493.         case OM_DISPOSE:               return (mDispose(cl, obj, (APTR)msg));
  494.         case MUIM_LocksWin_Update:     return (mUpdate(cl, obj, (APTR)msg));
  495.         case MUIM_LocksWin_Print:      return (mPrint(cl, obj, (APTR)msg));
  496.         case MUIM_LocksWin_Remove:     return (mRemove(cl, obj, (APTR)msg));
  497.         case MUIM_LocksWin_ListChange: return (mListChange(cl, obj, (APTR)msg));
  498.     }
  499.  
  500.     return (DoSuperMethodA(cl, obj, msg));
  501. }
  502.  
  503. void PrintLocks( char *filename )
  504. {
  505.     BPTR handle;
  506.  
  507.     if (handle = HandlePrintStart(filename)) {
  508.         struct LocksCallbackUserData ud;
  509.  
  510.         ud.ud_Shown = 0;
  511.         ud.ud_Hidden = 0;
  512.         ud.ud_Pattern = "#?";
  513.         ud.ud_Handle = handle;
  514.  
  515.         PrintFOneLine(handle, "\n  Address   Access         Path\n\n");
  516.         IterateList(PrintCallback, &ud);
  517.     }
  518.  
  519.     HandlePrintStop();
  520. }
  521.  
  522. void SendLockList( void )
  523. {
  524.     IterateList(SendCallback, NULL);
  525. }
  526.  
  527. ULONG CountLocks( UBYTE *pattern )
  528. {
  529.     struct LocksCallbackUserData ud;
  530.  
  531.     ud.ud_Pattern = pattern;
  532.     ud.ud_Shown = 0;
  533.     ud.ud_Hidden = 0;
  534.  
  535.     IterateList(CountCallback, &ud);
  536.  
  537.     return ud.ud_Shown;
  538. }
  539.  
  540. void RemoveLock( UBYTE *addr )
  541. {
  542.     struct LocksCallbackUserData ud;
  543.  
  544.     ud.ud_Pattern = addr;
  545.     ud.ud_Shown = 0;
  546.     ud.ud_Hidden = 0;
  547.  
  548.     IterateList(RemoveCallback, &ud);
  549. }
  550.  
  551.